﻿using System;
using System.Threading;
using System.Threading.Tasks;
using Model.Extensions;
using Model.Nova;
using Network;
using Network.Messages.Nova;
using Network.Utilities;
using Providers.Nova.Client;
using Providers.Nova.Modules;

namespace Managers.Nova.Client
{
    public sealed class NovaManager : Manager<NovaProvider>
    {
        public NovaManager(NetworkPeer network)
            : base(new NovaProvider(network))
        {
            Network.OnConnected += (s, e) => { OnConnected?.Invoke(s, e); };
            Provider.OnIntroductionCompleted +=
                (s, e) => { OnIntroductionCompleted?.Invoke(s, e); };
            Provider.OnNatTraversalSucceeded +=
                (s, e) => { OnNatTraversalSucceeded?.Invoke(s, e); };
            
            Provider.OnSeverInfoRecived += Provider_OnSeverInfoRecived;
            Provider.OnNoManOnDutyRegistrationCompletedEvent +=
                (s, e) => { OnNoManOnDutyRegistrationCompletedEvent?.Invoke(s, e); };
        }

        private double _nextReciveTime;
        public double Now
        {
            get
            {
                var dnow = NetTime.Now;
                var now = (float)dnow;
                return now;
            }
        }
        private void Provider_OnSeverInfoRecived(object sender, SeverInfoArgs e)
        {
            OnSeverInfoRecived?.Invoke(sender, e);
            _nextReciveTime = Now +0.5;
        }

        /// <summary>
        ///     连接
        /// </summary>
        /// <param name="novaId"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        // TODO: Redo this
        public Task<IntroducerIntroductionCompletedEventArgs> RequestIntroductionAsTask(string novaId, string password)
        {
            var tcs = RegisterAsTask(ref OnIntroductionCompleted);

            var childTask = Task.Factory.StartNew(() =>
            {
                var clientMachine = new Machine
                {
                    Identity = MachineIdentity.GetCurrentIdentity(),
                    PrivateEndPoint = Network.GetInternalEndPoint()
                };

                var serverMachine = new Machine
                {
                    NovaId = novaId,
                    PasswordHash = HashUtil.ComputeHash(password, HashType.SHA512)
                };

                Network.SendUnconnectedMessage(
                    new RequestIntroducerIntroductionMessage
                    {
                        ClientMachine = clientMachine,
                        ServerMachine = serverMachine
                    },
                    Config.GetIPEndPoint("IntroducerEndPoint"));
            }, TaskCreationOptions.AttachedToParent);

            return tcs.Task;
        }

        public void TestConnectToServer()
        {
            Network.Connect((Config.GetIPEndPoint("IntroducerEndPoint")));
        }

        public void ResetConnection()
        {
            Network.DisconnectConnection();
        }

        private Timer _timer;

        public void StartKeepConnectToServer(int timeTick)
        {
            //3、开始心跳
            _timer = new Timer(TimeTick, null, 0, timeTick); //实例化Timer类，设置间隔时间为timeTick毫秒；   
        }
        
        private void TimeTick(object state)
        {
            try
            {
                RequestServerInfo();
                FlagSeverAlive = (Now < _nextReciveTime);
            }
            catch (Exception )
            {
                // ignored
            }
        }

        public bool FlagSeverAlive
        {
            set
            {
                if (value == _flagSeverAlive)
                {
                    return;
                }
                OnServerStatusChanged?.Invoke(this, new ServerAliveStatusArgs() { FlagAlive = value });
                _flagSeverAlive = value;
            }
        }

        public void StopTimer()
        {
            _timer?.Dispose();
        }


        private string _identityHis = string.Empty;
        private bool _flagSeverAlive;

        public void RequestServerInfo()
        {
            if (string.IsNullOrEmpty(_identityHis))
            {
                _identityHis = MachineIdentity.GetCurrentIdentity();
            }
            Network.SendUnconnectedMessage(new RequestSelfMachineInfoMessage {Identity = _identityHis},
                Config.GetLocalHost());
            
        }
        public void RequestNewPassword()
        {
            if (string.IsNullOrEmpty(_identityHis))
            {
                _identityHis = MachineIdentity.GetCurrentIdentity();
            }
            Network.SendUnconnectedMessage(new RequestSelfMachineNewPassword { Identity = _identityHis },
                Config.GetLocalHost());
        }
        //add 2017年3月27日9:50:10
        public Task<SeverInfoArgs> RequestServerInfoAsTask()
        {
            var tcs = RegisterAsTask(ref OnSeverInfoRecived);

            var childTask = Task.Factory.StartNew(() =>
            {
                var identity = MachineIdentity.GetCurrentIdentity();
                Network.SendUnconnectedMessage(new RequestSelfMachineInfoMessage {Identity = identity},
                    Config.GetLocalHost());
            }, TaskCreationOptions.AttachedToParent);

            return tcs.Task;
        }

        public void AskServerShutdown()
        {
            Network.SendUnconnectedMessage(new AskServerShutdownMessage(),
                   Config.GetLocalHost());
        }

        public Task<NoManOnDutyRegistStatusArgs> RegisterNoManOnDutyAsTask(string userName, string password)
        {
            var tcs = RegisterAsTask(ref OnNoManOnDutyRegistrationCompletedEvent);

            var childTask = Task.Factory.StartNew(() =>
            {
                var identity = MachineIdentity.GetCurrentIdentity();
                var noManMachine = new Machine
                {
                    Identity = identity,
                    NovaId = userName,
                    Password = password,
                    PasswordHash = HashUtil.ComputeHash(password, HashType.SHA512)
                };
                Network.SendUnconnectedMessage(
                    new RequsetNoManOnDutyIntroducerRegistrationMessage {Machine = noManMachine},
                    Config.GetIPEndPoint("IntroducerEndPoint"));
            }, TaskCreationOptions.AttachedToParent);

            return tcs.Task;
        }

        public event EventHandler<ConnectedEventArgs> OnConnected;
        public event EventHandler<IntroducerIntroductionCompletedEventArgs> OnIntroductionCompleted;
        public event EventHandler<NatTraversedEventArgs> OnNatTraversalSucceeded;

        public event EventHandler<SeverInfoArgs> OnSeverInfoRecived;
        public event EventHandler<NoManOnDutyRegistStatusArgs> OnNoManOnDutyRegistrationCompletedEvent;
        public event EventHandler<ServerAliveStatusArgs> OnServerStatusChanged;
    }

    public class ServerAliveStatusArgs : EventArgs
    {
        public bool FlagAlive;
    }
}
